﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;

namespace CrazyDrawShape
{
    /// <summary>
    /// DrawLineControl.xaml 的交互逻辑
    /// </summary>
    public partial class DrawLineControl : UserControl
    {
        private enum DrawType
        {
            Draw,
            Edit
        }
        private enum EditType
        {
            Point1,
            Point2,
            Edge,
            None
        }
        private class LinePoint
        {
            public Point Point { set; get; }
            public Path Circle { set; get; }

            public LinePoint()
            {
                Path circle = new Path { Stroke = Brushes.Red, StrokeThickness = 1, Fill = Brushes.Red, ClipToBounds = true };
                Circle = circle;
            }
        }
        Path line = new Path { Stroke = Brushes.Red, StrokeThickness = 2, Fill = Brushes.Transparent, Opacity = 0.5, ClipToBounds = true };
        Path lineTransparent = new Path { Stroke = Brushes.Transparent, StrokeThickness = 10, Fill = Brushes.Transparent, Opacity = 0.5, ClipToBounds = true };
        LinePoint p1 = new LinePoint();
        LinePoint p2 = new LinePoint();
        bool isDown = false;
        bool isRun = false;
        Point downPoint;
        DrawType drawType = DrawType.Draw;
        EditType editType = EditType.None;

        public DrawLineControl()
        {
            InitializeComponent();
            this.lineTransparent.MouseEnter += LineTransparentMouseEnter;
            this.lineTransparent.MouseLeave += LineTransparentMouseLeave;
        }

        private void LineTransparentMouseLeave(object sender, MouseEventArgs e)
        {
            this.isRun = false;
        }

        private void LineTransparentMouseEnter(object sender, MouseEventArgs e)
        {
            this.isRun = true;
        }

        private void DrawClick(object sender, RoutedEventArgs e)
        {
            this.drawType = DrawType.Draw;
        }

        private void EditClick(object sender, RoutedEventArgs e)
        {
            this.drawType = DrawType.Edit;
        }

        private double PPDistance(Point p1, Point p2)
        {
            return Math.Sqrt(Math.Pow(p1.X - p2.X, 2) + Math.Pow(p1.Y - p2.Y, 2));
        }

        private EditType GetEditType(Point point)
        {
            double distance = 5;
            if (PPDistance(point, p1.Point) < distance)
            {
                return EditType.Point1;
            }
            else if (PPDistance(point, p2.Point) < distance)
            {
                return EditType.Point2;
            }
            else if (this.isRun)
            {
                return EditType.Edge;
            }
            else
            {
                return EditType.None;
            }
        }

        private void MainGridAddChildren()
        {
            this.mainGrid.Children.Clear();
            this.mainGrid.Children.Add(this.line);
            this.mainGrid.Children.Add(this.p1.Circle);
            this.mainGrid.Children.Add(this.p2.Circle);
            this.mainGrid.Children.Add(this.lineTransparent);
        }

        private void GridMouseDown(object sender, MouseButtonEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed)
            {
                this.downPoint = e.GetPosition(mainGrid);
                this.isDown = true;
                switch (this.drawType)
                {
                    case DrawType.Draw:
                        MainGridAddChildren();
                        this.line.Data = null;
                        this.lineTransparent.Data = null;
                        this.p1.Circle.Data = null;
                        this.p2.Circle.Data = null;
                        break;
                    case DrawType.Edit:
                        this.editType = GetEditType(this.downPoint);
                        break;
                }
            }
        }

        private void GridMouseUp(object sender, MouseButtonEventArgs e)
        {
            this.isDown = false;
            this.editType = EditType.None;
        }

        private void DrawCirle(LinePoint point)
        {
            point.Circle.Data = new EllipseGeometry
            {
                RadiusX = 3,
                RadiusY = 3,
                Center = point.Point
            };
        }
       
        private void GridMouseMove(object sender, MouseEventArgs e)
        {
            if (this.isDown)
            {
                switch (this.drawType)
                {
                    case DrawType.Draw:
                        {
                            this.p1.Point = new Point(this.downPoint.X, this.downPoint.Y);
                            DrawCirle(this.p1);
                            this.p2.Point = e.GetPosition(mainGrid);
                            DrawCirle(this.p2);
                            this.line.Data = new LineGeometry { StartPoint = this.p1.Point, EndPoint = this.p2.Point };
                            this.lineTransparent.Data = new LineGeometry { StartPoint = this.p1.Point, EndPoint = this.p2.Point };
                        }
                        break;
                    case DrawType.Edit:
                        Point curPoint = e.GetPosition(mainGrid);
                        switch (this.editType)
                        {
                            case EditType.Point1:
                                {
                                    this.p1.Point = new Point(curPoint.X, curPoint.Y);
                                    DrawCirle(this.p1);
                                    this.line.Data = new LineGeometry { StartPoint = this.p1.Point, EndPoint = this.p2.Point };
                                    this.lineTransparent.Data = new LineGeometry { StartPoint = this.p1.Point, EndPoint = this.p2.Point };
                                }
                                break;
                            case EditType.Point2:
                                {
                                    this.p2.Point = new Point(curPoint.X, curPoint.Y);
                                    DrawCirle(this.p2);
                                    this.line.Data = new LineGeometry { StartPoint = this.p1.Point, EndPoint = this.p2.Point };
                                    this.lineTransparent.Data = new LineGeometry { StartPoint = this.p1.Point, EndPoint = this.p2.Point };
                                }
                                break;
                            case EditType.Edge:
                                {
                                    double diffX = curPoint.X - this.downPoint.X;
                                    double diffY = curPoint.Y - this.downPoint.Y;
                                    this.p1.Point = new Point(this.p1.Point.X + diffX, this.p1.Point.Y + diffY);
                                    DrawCirle(this.p1);
                                    this.p2.Point = new Point(this.p2.Point.X + diffX, this.p2.Point.Y + diffY);
                                    DrawCirle(this.p2);
                                    this.line.Data = new LineGeometry { StartPoint = this.p1.Point, EndPoint = this.p2.Point };
                                    this.lineTransparent.Data = new LineGeometry { StartPoint = this.p1.Point, EndPoint = this.p2.Point };
                                    this.downPoint = curPoint;
                                }
                                break;
                            case EditType.None:
                                break;
                        }
                        break;
                }
            }
        }
    }
}